package com.swak.rabbit.message;

import java.util.List;
import java.util.Map;
import java.util.UUID;

import com.rabbitmq.client.AMQP.BasicProperties;
import com.swak.App;
import com.swak.Constants;
import com.swak.rabbit.AmqpException;
import com.swak.utils.Lists;
import com.swak.utils.StringUtils;

import lombok.Getter;
import lombok.Setter;
import lombok.experimental.Accessors;

/**
 * 基础的消息 (不可序列化，仅仅作为发送消息的载体)
 * 
 * @author lifeng
 */
@Getter
@Setter
@Accessors(chain = true)
public class Message {

	// 基本参数
	private BasicProperties properties;
	private byte[] payload; // 消息的内容
	private String id; // 设置到 messageId 中
	private Integer deliveryMode = 2; // 发布模式1(不持久化)， 2(持久化) 默认是持久化的消息，可以更改
	private Integer priority; // 消息的优先级 0 - 9
	private String expiration; // 消息的 ttl (s)

	// 重试队列
	private String origin;
	private String retryQueue;

	// 消费重试的次数
	private Integer consumeRetrys;

	// 发送重试 -- 默认设置为3次，小于0 则不重试发送
	private int publishRetrys = 3;

	public String getId() {
		if (id != null && properties == null) {
			throw new AmqpException("Invoke Message.build to Finish Message Init.");
		}
		if (properties != null) {
			return properties.getMessageId();
		}
		return StringUtils.EMPTY;
	}

	/**
	 * 将 object 序列化为 字节码，使用默認的序列化方式
	 * 
	 * @param payload
	 * @return
	 */
	public Message object2Payload(Object payload) {
		this.payload = App.serialize(payload);
		return this;
	}

	/**
	 * 将 object 序列化为 字节码，使用默認的序列化方式
	 * 
	 * @param payload
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public <T> T payload2Object() {
		return (T) App.deserialize(payload);
	}

	/**
	 * 重试的请求参数
	 * 
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public Message retryMessage() {
		Object deadQueue = null;
		if (properties.getHeaders() != null) {
			deadQueue = properties.getHeaders().get("x-first-death-queue");
			// bug 如果是延迟队列则需要获取第一个消费失败的队列（rejected， 这个才是真实的消费队列）
			Object reason = properties.getHeaders().get("x-first-death-reason");
			if (reason != null && "expired".equals(reason.toString())) {
				Object realDeadQueue = null;
				List<Map<String, Object>> deaths = (List<Map<String, Object>>) properties.getHeaders().get("x-death");
				if (!Lists.isEmpty(deaths)) {
					for (Map<String, Object> death: deaths) {
						reason = death.get("reason");
						if (reason != null && "rejected".equals(reason.toString())) {
							realDeadQueue = death.get("queue");
							break;
						}
					}
				}
				deadQueue = realDeadQueue != null ? realDeadQueue : deadQueue;
			}
		}
		String $deadQueue = null;
		if (deadQueue != null && StringUtils.isNotBlank($deadQueue = String.valueOf(deadQueue))
				&& !com.swak.rabbit.Constants.isRetryMessage($deadQueue)) {
			return this.setOrigin($deadQueue);
		}
		return this;
	}

	/**
	 * 使用 build 之后消息才是完整的消息 如果没于设置id，则使用uuid来设置
	 * 
	 * @return
	 */
	public Message build() {
		if (properties == null) {
			id = StringUtils.isBlank(id) ? UUID.randomUUID().toString() : id;
			properties = new BasicProperties(null, Constants.DEFAULT_ENCODING.name(), null, deliveryMode, priority,
					null, null, expiration, id, null, null, null, null, null);
		}
		return this;
	}

	/**
	 * 设置发送参数
	 * 
	 * @param pendingConfirm
	 */
	public void bindPendingConfirm(PendingConfirm pendingConfirm) {
		pendingConfirm.setDeliveryMode(this.deliveryMode);
		pendingConfirm.setPriority(this.priority);
		pendingConfirm.setExpiration(this.expiration);
		pendingConfirm.setPayload(this.payload);
		pendingConfirm.setRetryTimes(this.publishRetrys);
	}

	/**
	 * 创建一个空消息
	 */
	public static Message of() {
		return new Message();
	}
}